# Copyright (c) 2019 Presto Labs Pte. Ltd.
# Author: xguo

import datetime
import functools

from coin.exchange.kraken.kr_rest.currency import KrakenCurrency
from coin.exchange.kraken_futures.kr_rest.contract_util import (
    guess_kraken_futures_product_code,
    expiry_str_to_datetime,
    parse_kraken_futures_native_symbol,
    form_kraken_futures_native_symbol,
)

from coin.exchange.base.kr_rest.futures_product import (NativeFuturesProduct,
                                                        NormFuturesProduct,
                                                        parse_futures_product_symbol)
from coin.exchange.kraken_futures.kr_rest.native_private_client import (KrakenFuturesProductCode)


class KrakenFuturesProduct(NativeFuturesProduct):
  _exchange = 'Kraken'
  NativeCurrencyType = KrakenCurrency

  def __init__(
      self,
      base: KrakenCurrency,
      quote: KrakenCurrency,
      expiry: datetime.datetime,
      product_code: KrakenFuturesProductCode,
  ):
    assert isinstance(base, KrakenCurrency), type(base)
    assert isinstance(quote, KrakenCurrency), type(quote)
    assert isinstance(expiry, datetime.datetime), type(expiry)
    assert isinstance(product_code, KrakenFuturesProductCode), type(product_code)
    native_symbol = form_kraken_futures_native_symbol(base, quote, expiry, product_code)
    self._product_code = product_code
    super().__init__(base=base, quote=quote, expiry=expiry, native_symbol=native_symbol)

  @property
  def native_currency_pair(self):
    currency_pair = '%s-%s' % (self.base.native_currency, self.quote.native_currency)
    return currency_pair

  @property
  def product_code(self):
    return self._product_code

  def is_inverse_futures(self):
    inverted = (KrakenFuturesProductCode.PERPETUAL_INVERSE_FUTURES,
                KrakenFuturesProductCode.INVERSE_FUTURES)
    return self._product_code in inverted

  @classmethod
  @functools.lru_cache(maxsize=256)
  def FromProductImpl(cls, product, current_datetime):
    assert isinstance(product, NormFuturesProduct), type(product)
    product_code = guess_kraken_futures_product_code(product.quote, product.expiry)
    return cls(product.base, product.quote, product.expiry, product_code)

  @classmethod
  @functools.lru_cache(maxsize=256)
  def FromStrProductImpl(cls, product, current_datetime):
    parsed_result = parse_futures_product_symbol(product)
    base = KrakenCurrency.FromStr(parsed_result['base'], current_datetime)
    quote = KrakenCurrency.FromStr(parsed_result['quote'], current_datetime)
    expiry = expiry_str_to_datetime(parsed_result['expiry'], current_datetime)
    product_code = guess_kraken_futures_product_code(quote, expiry)
    return cls(base, quote, expiry, product_code)

  @classmethod
  @functools.lru_cache(maxsize=256)
  def FromStrNativeProductImpl(cls, product, current_datetime):
    assert isinstance(product, str), product
    parsed_result = parse_kraken_futures_native_symbol(product, current_datetime)
    return cls(**parsed_result)
